home *** CD-ROM | disk | FTP | other *** search
- ; DIRCOMP.ASM -- Lists two directories side by side
- ; =================================================
-
- CSEG Segment
- Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
- Org 0080h
- Parameter Label Byte ; Parameter is here
- Org 0100h
- Entry: Jmp Begin ; Entry Point
-
- ; Most Data (some more at end of program)
- ; ---------------------------------------
-
- db "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
- db " Programmed by Charles Petzold ",1Ah
- SyntaxMsg db "Syntax: DIRCOMP filespec filespec$"
- DosVersMsg db "DIRCOMP: Needs DOS 2.0 +$"
- FileSpecMsg db "DIRCOMP: Bad file name$"
- TooManyMsg db "DIRCOMP: Too many files$"
- MemAllocMsg db "DIRCOMP: Not enough memory$"
- Delimiters db 9,' ,;='
- FileList1 dd 0, ? ; Storage of found files
- FileList2 dd 0, ?
- FileCount1 dw 0 ; Count of found files
- FileCount2 dw 0
- Append db '\*.*', 0
-
- ; Check DOS Version
- ; -----------------
-
- Begin: Mov AH, 30h ; Check for DOS Version
- Int 21h ; through DOS call
- Cmp AL, 2 ; See if it's 2.0 or above
- Jae DosVersOK ; If so, continue
- Mov DX, Offset DosVersMsg ; Error message
-
- ErrorExit: Mov AH, 9 ; Print String function call
- Int 21h ; Do it
- Int 20h ; And exit prematurely
-
- ; Parse Command Line to get file specifications
- ; ---------------------------------------------
-
- DosVersOK: Cld ; Directions forward
- Mov SI, Offset Parameter ; Parameter string
- Lodsb ; Length of Parameter
- Mov BL, AL ; Make BX the length
- Sub BH, BH
- Mov Word Ptr [SI + BX], 0D20h ; Put blank at end
-
- Mov DI, Offset FileSpec1 ; Destination of first spec
- Call GetFileSpec ; Transfer it and fix it up
- Mov DI, Offset FileSpec2 ; Destination of second spec
- Call GetFileSpec ; Transfer it and fix it up
-
- ; De-Allocate rest of memory
- ; --------------------------
-
- Mov DX, Offset MemAllocMsg ; Possible error message
- Mov SP, Offset StackTop ; Bring in stack pointer
- Mov BX, SP ; Also end of needed memory
- Add BX, 15 ; Add 15 for truncation
- Mov CL, 4 ; Shift 4 bits right
- Shr BX, CL
- Mov AH, 4Ah ; Change memory size
- Int 21h ; through DOS
- Jc ErrorExit ; If problem, terminate
-
- ; Find Files from file specification
- ; ----------------------------------
-
- Mov DX, Offset DTABuffer ; Set File Find buffer
- Mov AH, 1Ah ; by calling DOS
- Int 21h
-
- Mov DX, Offset FileSpec1 ; First file specification
- Call GetFilesAndSort ; Do as it says
- Mov Word Ptr [FileList1 + 2], AX ; Segment of file list
- Mov [FileCount1], CX ; Number of files
-
- Mov DX, Offset FileSpec2 ; Second file specification
- Call GetFilesAndSort ; Do it again
- Mov Word Ptr [FileList2 + 2], AX ; Segment of file list
- Mov [FileCount2], CX ; Number of files
-
- ; Now Display List on Screen
- ; --------------------------
-
- DoAnother: Lea DI, DisplayString ; Destination of display line
- Mov AL, ' '
- Cmp [FileCount1],0 ; See if any more left
- Jz FirstColDone ; If so, first column is blank
- Cmp [FileCount2],0 ; See if second is done
- Jz ListOnly1 ; If so, 2nd column is blank
- Push SI
- Push DI
- Push DS
- Push ES
- Les DI, [FileList2] ; Address of second list
- Lds SI, [FileList1] ; Address of first list
- Mov CX, 12 ; Number of bytes to compare
- Repz Cmpsb ; Compare them
- Pop ES ; Get back registers
- Pop DS
- Pop DI
- Pop SI
- Jb ListOnly1 ; If file 1 < file 2, list 1
- Ja ListOnly2 ; If file 1 > file 2, list 2
- Call ListFile1 ; Put first in display string
- Stosb ; Put a blank after it
- Jmp Short DoSecond ; Now do second file
-
- FirstColDone: Cmp [FileCount2], 0 ; See if second done also
- Jz AllDone ; If so, we're done
-
- ListOnly2: Mov CX, 40 ; If not, store 40 blanks
- Rep Stosb
-
- DoSecond: Call ListFile2 ; Put 2nd file in display str
- Jmp Short WriteCRLF ; And append a CR/Lf
-
- ListOnly1: Call ListFile1 ; Put 1st file in display str
- Mov CX, 40 ; Blank out second half
- Rep Stosb
-
- WriteCRLF: Mov AX, 0A0Dh ; Put CR/LF at end of string
- Stosw
-
- SpillOut: Lea DX, DisplayString ; Address of display string
- Mov CX, 81 ; Number of characters
- Mov BX, 1 ; Standard output
- Mov AH, 40h ; Write to screen
- Int 21h ; through DOS
- Jmp DoAnother ; And do the next one
-
- AllDone: Int 20h ; All done -- terminate
-
- ; SUBROUTINE: Get File Spec (uses DI to point to destination)
- ; -----------------------------------------------------------
-
- GetFileSpec: Mov DX, DI ; Save pointer in DX
-
- Search: Call ScanParam ; Check next byte
- Je Search ; If delimiter, keep searching
-
- SearchEnd: Stosb ; Save the character
- Call ScanParam ; Check the next byte
- Jne SearchEnd ; If not delimiter, continue
- Mov Byte Ptr [DI], 0 ; Make it an ASCIIZ string
- Push SI ; Save parameter pointer
- Mov SI, 1 + Offset Append ; Set to *.* string
- Mov CX, 4 ; Possible 4 bytes to move
- Cmp Byte Ptr [DI - 1], ':' ; Do it if last character is :
- Jz AppendStuff
- Cmp Byte Ptr [DI - 1], '\' ; Or if last character is \
- Jz AppendStuff
- Mov AX, 4300h ; Get file attribute
- Int 21h ; through DOS
- Jc FixUpDone ; If error, do no more
- Test CL, 10h ; See if it's directory
- Jz FixUpDone ; If not, do no more
- Dec SI ; If so, append \*.*
- Inc CX ; which has five characters
-
- AppendStuff: Rep Movsb ; Append string to file spec
-
- FixUpDone: Pop SI ; And done with this stuff
- Ret
-
- ; SUBROUTINE: Scan Parameter
- ; --------------------------
-
- ScanParam: Push DI ; Save destination pointer
- Lodsb ; Get byte from parameter
- Cmp AL, 13 ; See if end of parameter
- Jne NotAtEnd ; If so, got an error
- Mov DX, Offset SyntaxMsg ; Load up error message
- Jmp ErrorExit ; and exit
-
- NotAtEnd: Mov DI, Offset Delimiters ; Check if delimiter
- Mov CX, 5 ; There are 5 of them
- Repne Scasb ; Scan the string
- Pop DI ; Get back pointer
- Ret ; And return
-
- ; SUBROUTINE: Get Files and Sort
- ; ------------------------------
-
- GetFilesAndSort:Push ES
- Mov BX, 1000h ; Try to allocate 64K memory
- Mov AH, 48h ; through DOS
- Int 21h
- Jnc AllocateOK ; If no error, we've got it
- Mov AH, 48h ; Otherwise allocate
- Int 21h ; as much as possible
-
- AllocateOK: Mov CL, 4 ; Turn BX into an offset
- Shl BX, CL
- Sub BX, 20 ; Take away 20 bytes
- Mov ES, AX ; Set ES to memory segment
- Sub DI, DI ; Point to beginning
- Sub BP, BP ; File Counter
- Mov CX, 06h ; Normal, hidden, system files
- Mov AH, 4Eh ; Find first file
-
- FindFile: Int 21h ; Call DOS to find file
- Jnc Continue ; If no error continue
- Cmp AX, 18 ; If no more files
- Jz NoMoreFiles ; get out of the loop
- Mov DX, Offset FileSpecMsg ; Error message otherwise
- Jmp ErrorExit ; Exit and print message
-
- Continue: Cmp DI, BX ; See if end of segment
- Jb StillOK ; If not, continue
-
- TooManyFiles: Mov DX, Offset TooManyMsg ; Otherwise error message
- Jmp ErrorExit ; And terminate
-
- StillOK: Inc BP ; Kick up file counter
- Mov SI, 30+Offset DTABuffer ; Points to filename
- Mov CX, 12 ; 12 bytes to transfer
-
- TransName: Lodsb ; Get a byte
- Or AL, AL ; See if it's zero
- Jz NameDone ; If so, transfer done
- Cmp AL, '.' ; See if it's period
- Jnz NotPeriod ; If not keep going
- Sub CX, 3 ; If period, adjust counter
- Mov AL, ' ' ; Pad names with blanks
- Rep Stosb
- Add CX, 3 ; Re-adjust counter
- Jmp TransName ; And continue
-
- NotPeriod: Stosb ; If not period, just store it
- Loop TransName ; And keep going
-
- NameDone: Mov AL, ' ' ; Pad end of name with blanks
- Rep Stosb
- Mov SI, 22+Offset DTABuffer ; Point to time/date/size
- Mov CX, 4 ; Save that stuff too
- Rep Movsw
- Mov AH, 4Fh ; Find next file
- Jmp FindFile
-
- NoMoreFiles: Mov BX, DI ; End of file storage
- Add BX, 15 ; Convert to paragraph
- Mov CL, 4
- Shr BX, CL
- Mov AH, 4Ah ; Re-adjust memory
- Int 21h
-
- ; Sort Files
- ; ----------
-
- Push DS ; Save DS
- Push ES
- Pop DS ; Point DS to files
- Sub DI, DI ; This is the beginning
- Mov CX, BP ; Number of files to sort
- Jcxz AllSorted ; If no files, we're done
- Dec CX ; Loop needs one less than CX
- Jcxz AllSorted ; But zero means only one file
-
- SortLoop1: Push CX ; Save the file counter
- Mov SI, DI ; Set source to destination
-
- SortLoop2: Add SI, 20 ; Set source to next file
- Push CX ; Save the counter,
- Push SI ; compare source,
- Push DI ; and compare destination
- Mov CX, 20 ; 20 characters to compare
- Repz Cmpsb ; Do the compare
- Jae NoSwitch ; Jump if already in order
- Pop DI ; Get back these registers
- Pop SI
- Push SI ; And push them again for move
- Push DI
- Mov CX, 20 ; 20 characters
-
- SwitchLoop: Mov AL, ES:[DI] ; Character from destination
- Movsb ; Source to destination
- Mov DS:[SI - 1], AL ; Character to source
- Loop SwitchLoop ; For the rest of the line
-
- NoSwitch: Pop DI ; Get back the registers
- Pop SI
- Pop CX
- Loop SortLoop2 ; And loop for next file
- Pop CX ; Get back file counter
- Add DI, 20 ; Compare with next file
- Loop SortLoop1 ; And loop again
-
- AllSorted: Pop DS ; Get back to normal
- Mov AX, ES ; File segment in AX
- Pop ES
- Mov CX, BP ; File count in CX
- Ret
-
- ; SUBROUTINES for listing files on screen
- ; ---------------------------------------
-
- ListFile1: Push DS
- Lds SI, [FileList1] ; Set to address of list
- Call ListFile ; Put it into DisplayString
- Pop DS
- Mov Word Ptr [FileList1], SI ; Save new pointer
- Dec [FileCount1] ; Decrement count
- Ret
-
- ListFile2: Push DS
- Lds SI, [FileList2] ; Set to address of list
- Call ListFile ; Put it into DisplayString
- Pop DS
- Mov Word Ptr [FileList2], SI ; Save new pointer
- Dec [FileCount2] ; Decrement count
- Ret
-
- ListFile: Push AX
- Push SI
- Push DI
- Mov CX, 12 ; 12 characters in file name
- Rep Movsb ; Transfer them
- Mov AL, ' ' ; Blank out the rest
- Mov CX, 27
- Rep Stosb
-
- Sub DI, 6 ; Point to time destination
- Lodsw ; Get the coded time
-
- Mov BL, 01Fh ; AND mask for hours
- Mov BH, '0' ; Zero-blank indicator
- Mov CL, 11 ; Shift value for hours
- Sub DL, DL ; Offset for hours
- Mov DH, ':' ; Following character
- Call DateTime ; Do the transfer routine
-
- Mov BX, 3Fh ; Zero OK / AND Mask for minutes
- Mov CL, 5 ; Shift value of minutes
- Mov DH, ' ' ; Following character
- Call DateTime ; Do the transfer routine
-
- Sub DI, 16 ; Point to date destination
- Lodsw ; Get the coded date
-
- Mov BL, 0Fh ; AND mask for month
- Mov BH, '0' ; Zero-blank indicator
- Mov CL, 5 ; Shift value for month
- Mov DH, '-' ; Following character
- Call DateTime ; Do the transfer routine
-
- Mov BX, 1Fh ; Zero OK / AND mask for day
- Mov CL, 0 ; Shift value for day
- Call DateTime ; Do the transfer routine
-
- Mov BL, 7Fh ; AND mask for year
- Mov CL, 9 ; Shift value for year
- Mov DL, 80 ; Offset for year
- Mov DH, ' ' ; Following character
- Call DateTime ; Do the transfer routine
-
- Sub DI, 12 ; Point to end of file size space
- Lodsw ; Get low word
- Mov DX, AX ; Save it in DX
- Lodsw ; AX is high word, DX low word
- Mov BX, 10 ; Will divide by 10 for ASCII
- Std ; Direction backward
-
- AsciiLoop: Mov CX, DX ; Save low word in CX
- Sub DX, DX ; Zero out DX for division
- Div BX ; AX = quotient, DX = remainder
- Xchg AX, CX ; Now AX = low word, CX = quotient1
- Div BX ; AX = quotient2, DX = remainder
- Xchg AX, DX ; AX = remainder, DX = quotient2
- Add AL, '0' ; Adjust for ASCII
- Stosb ; Store it
- Mov AX, CX ; See if zero is left
- Or CX, DX
- Jnz AsciiLoop ; If not, continue
-
- Cld ; Get back to normal
- Pop DI
- Pop SI
- Pop AX
- Add SI, 20 ; Next file in list
- Add DI, 39 ; Next byte in destination
- Ret
-
- ; SUBROUTINE: Date and Time Display
- ; ---------------------------------
-
- DateTime: Push AX
- Push BX
- Push CX
- Push DX
- Shr AX, CL ; Shift word left by CL bits
- And AL, BL ; AND it with BL mask
- Add AL, DL ; Offset it by DL
- Sub AH, AH ; Zero out high byte
- Mov BL, 10 ; Divide by 10
- Div BL
- Add AX, '00' ; Convert to ASCII
- Cmp AL, BH ; Check Zero-Blank
- Jnz LeadingNonZero
- Mov AL, ' ' ; Put in blank instead of zero
-
- LeadingNonZero: Stosw ; Store the two bytes
- Mov AL, DH ; Get following character
- Stosb ; Store that also
- Pop DX
- Pop CX
- Pop BX
- Pop AX
- Ret
-
- ; Variable length data stored at end
- ; ----------------------------------
-
- Even
- FileSpec1 Label Byte
- FileSpec2 equ FileSpec1 + 80
- DTABuffer equ FileSpec2 + 80
- DisplayString equ DTABuffer + 43
- EndOfData equ DisplayString + 81
- StackTop equ EndOfData + 200h
- CSEG EndS ; End of the segment
- End Entry ; Denotes entry point
-